package com.msb.mall.order.service.impl;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.msb.common.constant.OrderConstant;
import com.msb.common.exception.NoStockExecption;
import com.msb.common.utils.R;
import com.msb.common.vo.MemberVO;
import com.msb.mall.order.Interceptor.AuthInterceptor;

import com.msb.mall.order.dto.OrderCreateTO;
import com.msb.mall.order.entity.OrderItemEntity;
import com.msb.mall.order.fegin.CartFeginService;
import com.msb.mall.order.fegin.MemberFeginService;
import com.msb.mall.order.fegin.ProductService;
import com.msb.mall.order.fegin.WareFeignService;
import com.msb.mall.order.service.OrderItemService;
import com.msb.mall.order.utils.OrderMsgConsumer;
import com.msb.mall.order.utils.OrderMsgProducer;
import com.msb.mall.order.vo.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.msb.common.utils.PageUtils;
import com.msb.common.utils.Query;

import com.msb.mall.order.dao.OrderDao;
import com.msb.mall.order.entity.OrderEntity;
import com.msb.mall.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {


    @Autowired
    MemberFeginService memberFeginService;

    @Autowired
    CartFeginService cartFeginService;

    @Autowired
    ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    StringRedisTemplate template;

    @Autowired
    ProductService productService;

    @Autowired
    OrderItemService orderItemService;

    @Autowired
    WareFeignService wareFeignService;

    @Autowired
    OrderMsgProducer orderMsgProducer;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }


    /**
     * 更新订单的状态信息
     * @param orderSn
     */

    public void updateOrderStatus(String orderSn,Integer status) {
        this.getBaseMapper().updateOrderStatus(orderSn,status);
    }

    @Override
    public void handleOrderComplete(String orderSn) {
        // 1.更新订单状态
        this.updateOrderStatus(orderSn,OrderConstant.OrderStateEnum.TO_SEND_GOODS.getCode());
        // TODO
        // 2.更新库存信息 库存数量递减

        // 3.购物车中的已经支付的商品移除

        // 4.更新会员积分 ....
    }


    @Override
    public PayVo getOrderPay(String orderSn) {
        // 根据订单号查询相关的订单信息
        OrderEntity orderEntity = this.getBaseMapper().selectOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        // 通过订单信息封装 PayVO对象
        PayVo payVo = new PayVo();
        payVo.setOut_trader_no(orderSn);
        payVo.setTotal_amount(orderEntity.getTotalAmount().setScale(2,BigDecimal.ROUND_UP).toString());
        // 订单名称和订单描述
        payVo.setBody(orderEntity.getOrderSn());
        payVo.setSubject(orderEntity.getOrderSn());
        return payVo;
    }

    /**
     * 获取订单确认页中需要获取的相关信息
     * @return
     */
    @Override
    public OrderConfirmVo comfirmOrder() {

        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
        MemberVO memberVO = AuthInterceptor.threadLocal.get();
        // 在主线程中获取 RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        CompletableFuture<Void> Future1 = CompletableFuture.runAsync(() -> {
            // RequestContextHolder 绑定主线程中的 RequestAttributes
            RequestContextHolder.setRequestAttributes(requestAttributes);
            // 1.查询当前登录用户对应的会员的地址信息
            Long id = memberVO.getId();
            List<MemberAddressVo> address = memberFeginService.getAddress(id);
            orderConfirmVo.setAddress(address);
        }, threadPoolExecutor);


        CompletableFuture<Void> Future2 = CompletableFuture.runAsync(() -> {
            // RequestContextHolder 绑定主线程中的 RequestAttributes
            RequestContextHolder.setRequestAttributes(requestAttributes);
            // 2.查询购物车中选中的商品信息
            List<OrderItemVo> userCartItems = cartFeginService.getUserCartItems();
            orderConfirmVo.setItems(userCartItems);
        }, threadPoolExecutor);

        // 3.计算订单的总金额和需要支付的总金额 VO自动计算

        // 主线程需要等待所有的子线程完成后继续
        CompletableFuture<Void> Future = CompletableFuture.allOf(Future1, Future2);
        try {
            Future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        //4.生成防重token
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        // 我们需要把这个Token信息存储在Redis中
        // order:token:用户编号
        template.opsForValue().set(OrderConstant.ORDER_TOKEN_PREFIX+":"+memberVO.getId(),token);
        // 然后我们需要将这个Token绑定在响应的数据对象中
        orderConfirmVo.setOrderToken(token);

        return orderConfirmVo;
    }

    /**
     * 提交商品订单，锁定库存，最后下单是否成功
     * @param vo
     * @return
     */
   // @GlobalTransactional
    @Transactional
    @Override
    public OrderResponseVO orderSubmit(OrderSubmitVO vo) throws NoStockExecption {

        OrderResponseVO responseVO = new OrderResponseVO();
        // 获取当前登录的用户信息
        MemberVO memberVO = AuthInterceptor.threadLocal.get();
        // 1.验证是否重复提交  保证Redis中的token 的查询和删除是一个原子性操作
        String key = OrderConstant.ORDER_TOKEN_PREFIX+":"+memberVO.getId();
        String script = "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        Long result = template.execute(new DefaultRedisScript<Long>(script, Long.class)
                , Arrays.asList(key)
                , vo.getOrderToken());
        if(result == 0){
            // 表示验证失败 说明是重复提交
            responseVO.setCode(1);
            return responseVO;
        }

        // 2.创建订单和订单项信息
        OrderCreateTO orderCreateTO = createOrder(vo);
        responseVO.setOrderEntity(orderCreateTO.getOrderEntity());

        // 3.保存订单信息
        saveOrder(orderCreateTO);
        // 4.锁定库存信息
        // 订单号  SKU_ID  SKU_NAME 商品数量
        // 封装 WareSkuLockVO 对象
        lockWareSkuStock(responseVO,orderCreateTO);

        int i=1/0;

        //5.订单成功后需要给 消息中间件发送延迟30分钟的关单消息
      orderMsgProducer.sendOrderMessage(orderCreateTO.getOrderEntity().getOrderSn());

        return responseVO;
    }


    /**
     * 锁定库存的方法
     * @param responseVO
     * @param orderCreateTO
     * @throws
     */
    private void lockWareSkuStock(OrderResponseVO responseVO, OrderCreateTO orderCreateTO)throws NoStockExecption {

        WareSkuLockVO wareSkuLockVO = new WareSkuLockVO();
        wareSkuLockVO.setOrderSN(responseVO.getOrderEntity().getOrderSn());
        List<OrderItemVo> orderItemVos = orderCreateTO.getOrderItemEntitys().stream().map(item -> {
            OrderItemVo itemVo = new OrderItemVo();
            itemVo.setSkuId(item.getSkuId());
            itemVo.setTitle(item.getSkuName());
            itemVo.setCount(item.getSkuQuantity());

            return itemVo;
        }).collect(Collectors.toList());
        wareSkuLockVO.setItems(orderItemVos);

        // 远程锁库存的操作
        R r = wareFeignService.orderLockStock(wareSkuLockVO);
        if (r.getcode() == 0) {
            // 表示锁定库存成功
            responseVO.setCode(0);// 表示 创建订单成功
        } else {
            // 表示锁定库存失败
            responseVO.setCode(2);
            throw new NoStockExecption(10000L);// 表示库存不足，锁定失败
        }

    }

    /**
     * 保存订单信息
     * @param orderCreateTO
     */
    private void saveOrder(OrderCreateTO orderCreateTO) {
         OrderEntity orderEntity = orderCreateTO.getOrderEntity();
        this.save(orderEntity);
        List<OrderItemEntity> orderItemEntitys = orderCreateTO.getOrderItemEntitys();
        orderItemService.saveBatch(orderItemEntitys);


    }

    /**
     * 创建订单和订单项信息
     * @param vo
     * @return
     */
    private OrderCreateTO createOrder(OrderSubmitVO vo) {
        OrderCreateTO createTO = new OrderCreateTO();

        // 创建订单
        OrderEntity orderEntity=buildOrder(vo);
        createTO.setOrderEntity(orderEntity);

        // 创建OrderItemEntity 订单项
        List<OrderItemEntity> orderItems=buildOrderItems(orderEntity.getOrderSn());
        createTO.setOrderItemEntitys(orderItems);

        // 根据订单项计算出支付总额   todo 这里没有经过各种优惠算出来的总价
        BigDecimal totalAmount = new BigDecimal(0);
        for (OrderItemEntity orderItem : orderItems) {

           BigDecimal multiply = orderItem.getSkuPrice().multiply(new BigDecimal(orderItem.getSkuQuantity()));
            totalAmount= totalAmount.add(multiply);
        }
        // todo 设置订单的总额
        orderEntity.setTotalAmount(totalAmount);

        return createTO;
    }


    /**
     * 通过购物车中选中的商品来创建对应的购物项信息
     * @param orderSn
     * @return
     */
    private List<OrderItemEntity> buildOrderItems(String orderSn) {
        ArrayList<OrderItemEntity> orderItemEntitys = new ArrayList<>();
        // 获取购物车中的商品信息 选中的
        List<OrderItemVo> userCartItems = cartFeginService.getUserCartItems();
        //收集spuId,并把重复的去掉
        if (userCartItems != null && userCartItems.size() > 0) {
            List<Long> spuIds = new ArrayList<>();
            for (OrderItemVo userCartItem : userCartItems) {
                if (!spuIds.contains(userCartItem.getSpuId())) {
                    spuIds.add(userCartItem.getSpuId());
                }
            }
            // 远程调用商品服务获取到对应的SPU信息Collectors
            Long[] spuIdsArray = new Long[spuIds.size()];
            spuIdsArray = spuIds.toArray(spuIdsArray);
            // 远程调用商品服务获取到对应的SPU信息
            List<OrderItemSpuInfoVO> spuInfos = productService.getOrderItemSpuInfoBySpuId(spuIdsArray);
           Map<Long, OrderItemSpuInfoVO> map = spuInfos.stream().collect(Collectors.toMap(OrderItemSpuInfoVO::getId, item -> item));
            for (OrderItemVo userCartItem : userCartItems) {
                // 获取到商品信息对应的 SPU信息
                OrderItemSpuInfoVO spuInfo = map.get(userCartItem.getSpuId());
                //传入商品信息和spu信息
                OrderItemEntity orderItemEntity=buildOrderItem(userCartItem,spuInfo);
                // 绑定对应的订单编号
                orderItemEntity.setOrderSn(orderSn);
                orderItemEntitys.add(orderItemEntity);
            }
        }
        return orderItemEntitys;
    }
    /**
     * 根据一个购物车中的商品创建对应的 订单项
     * @param userCartItem
     * @return
     */
    private OrderItemEntity buildOrderItem(OrderItemVo userCartItem, OrderItemSpuInfoVO spuInfo) {
        OrderItemEntity entity = new OrderItemEntity();
        // SKU信息
        entity.setSkuId(userCartItem.getSkuId());
        entity.setSkuName(userCartItem.getTitle());
        entity.setSkuPic(userCartItem.getImage());
        entity.setSkuQuantity(userCartItem.getCount());
        /**
         * 选择颜色:炫酷蓝
         * 选择版本:8G+256G
         * 选择版本:官方标配
         * 套　　装:套装1
         */
        List<String> skuAttr = userCartItem.getSkuAttr();
        //选择颜色:炫酷蓝;选择版本:8G+256G;选择版本:官方标配;套　　装:套装1
        String skuAttrStr = StringUtils.collectionToDelimitedString(skuAttr, ";");
        entity.setSkuAttrsVals(skuAttrStr);
        // SPU信息
        entity.setSpuId(spuInfo.getId());
        entity.setSpuBrand(spuInfo.getBrandName());
        entity.setCategoryId(spuInfo.getCatalogId());
        entity.setSpuPic(spuInfo.getImg());
        // 优惠信息 忽略
        // 积分信息
        entity.setGiftGrowth(userCartItem.getPrice().intValue());
        entity.setGiftIntegration(userCartItem.getPrice().intValue());
        entity.setSkuPrice(userCartItem.getPrice());
        return entity;

    }

    // 创建订单
    private OrderEntity buildOrder(OrderSubmitVO vo) {
        //todo 创建OrderEntity
        OrderEntity orderEntity = new OrderEntity();
        //todo 创建订单编号
        String orderSn = IdWorker.getTimeId();
        orderEntity.setOrderSn(orderSn);
        MemberVO memberVO = AuthInterceptor.threadLocal.get();
        // 设置会员相关的信息
        orderEntity.setMemberId(memberVO.getId());
        orderEntity.setMemberUsername(memberVO.getUsername());
        // 根据收获地址ID获取收获地址的详细信息
        MemberAddressVo memberAddressVo = memberFeginService.getAddressById(vo.getAddrId());
        orderEntity.setReceiverCity(memberAddressVo.getCity());
        orderEntity.setReceiverDetailAddress(memberAddressVo.getDetailAddress());
        orderEntity.setReceiverName(memberAddressVo.getName());
        orderEntity.setReceiverPhone(memberAddressVo.getPhone());
        orderEntity.setReceiverPostCode(memberAddressVo.getAreacode());
        orderEntity.setReceiverRegion(memberAddressVo.getRegion());
        orderEntity.setReceiverProvince(memberAddressVo.getProvince());
        // 设置订单的状态
        orderEntity.setStatus(OrderConstant.OrderStateEnum.FOR_THE_PAYMENT.getCode());

        return orderEntity;
    }




}